/****************************************************************************
 *   This file is part of Q2D.                                              *
 *                                                                          *
 *   Q2D is free software: you can redistribute it and/or modify            *
 *   it under the terms of the GNU General Public License as published by   *
 *   the Free Software Foundation, either version 3 of the License, or      *
 *   (at your option) any later version.                                    *
 *                                                                          *
 *   Q2D is distributed in the hope that it will be useful,                 *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of         *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the          *
 *   GNU General Public License for more details.                           *
 *                                                                          *
 *   You should have received a copy of the GNU General Public License      *
 *   along with Q2D.  If not, see <http://www.gnu.org/licenses/>.           *
 *                                                                          *
 ****************************************************************************/


#include "mysqlembeddeddatabase.h"

MySQLEmbeddedDatabase::MySQLEmbeddedDatabase() :
                QObject()
{

        //QCoreApplication::removeLibraryPath(QCoreApplication::applicationDirPath());
        //QCoreApplication::addLibraryPath(QCoreApplication::applicationDirPath());

        db = QSqlDatabase::addDatabase("QMYSQLE");

        db.setHostName(QDir::homePath() + "/.q2d/mysqle");
        bool ok = db.open();

        QSqlQuery query = db.exec("use q2d");

        if(query.isActive()){
                qDebug("q2d db present.");
        }else{
                qDebug("q2d db missing");

                createDatabase();
        }

        db.setDatabaseName("q2d");
        ok = db.open();

        if(ok){
                qDebug("connected");
        }else{
                qDebug("not connected");
        }

}

MySQLEmbeddedDatabase::~MySQLEmbeddedDatabase()
{
        db.close();
}

void MySQLEmbeddedDatabase::createDatabase(void)
{
        qDebug("Creating database...");

        QSqlQuery query;

        QFile sqlscript("tools/database_create.sql");

        if (!sqlscript.open(QIODevice::ReadOnly | QIODevice::Text)){
                qDebug("database script not found");
                return;
        }

        while(!sqlscript.atEnd()){
                QByteArray line = sqlscript.readLine();
                //qDebug(line);
                query.exec(line);
        }

}

bool MySQLEmbeddedDatabase::addWeapon(Weapon *weapon)
{
        QSqlQuery query;

        if(this->weaponTypeExist(*weapon->getWeaponType())){
                if( this->updateWeaponType(weapon->getWeaponType()) == false ){
                        qDebug("Error while updating the WeaponType.");
                        return false;
                }
        }else{
                if( this->addWeaponType(weapon->getWeaponType()) == false ){
                        qDebug("Error while adding the WeaponType.");
                        return false;
                }
        }

        if(this->weaponDamageTypeExist(*weapon->getDamageType())){
                if( this->updateWeaponDamageType(weapon->getDamageType()) == false ){
                        qDebug("Error while updating the WeaponDamageType.");
                        return false;
                }
        }else{
                if( this->addWeaponDamageType(weapon->getDamageType()) == false ){
                        qDebug("Error while adding the WeaponDamageType.");
                        return false;
                }
        }

        query.prepare("INSERT INTO weapon(wp_hash,wp_name,wp_desc,wp_type_hash,wp_price,"
                                          "wp_dmg_s,wp_dmg_m,wp_crit_fact,wp_crit_rng"
                                          "wp_range,wp_weight,wp_dmg_type_hash,wp_ba_bonus,wp_dmg_bonus) "
                        "VALUES(:hash,:name,:desc,:type_hash,:price,:dmg_s,:dmg_m,"
                        ":crit_fact,:crit_rng,:range,:weight,:dmg_type_hash,:ba_bonus,:dmg_bonus)");

        query.bindValue(":hash", weapon->getHexHash());
        query.bindValue(":name", weapon->getName());
        query.bindValue(":desc", weapon->getDescription());
        query.bindValue(":type_hash", weapon->getWeaponType()->getHexHash());
        query.bindValue(":price", weapon->getPrice());
        query.bindValue(":dmg_s", weapon->getDamageSmall());
        query.bindValue(":dmg_m", weapon->getDamageMedium());
        query.bindValue(":crit_fact", weapon->getCriticalFactor());
        query.bindValue(":crit_rng", weapon->getCriticalRange());
        query.bindValue(":range", weapon->getRange());
        query.bindValue(":weight", weapon->getWeight());
        query.bindValue(":dmg_type_hash", weapon->getDamageType()->getHexHash());
        query.bindValue(":ba_bonus", weapon->getBaBonus());
        query.bindValue(":dmg_bonus", weapon->getDmgBonus());

        if(query.exec()){
                weapon->setId(query.lastInsertId().toInt());
                return true;
        }else{
                return false;
        }
}

bool MySQLEmbeddedDatabase::removeWeapon(Weapon *weapon)
{
        QSqlQuery query;

        query.prepare("DELETE FROM weapon WHERE weapon.wp_hash = :hash");
        query.bindValue(":hash", weapon->getHexHash());

        if(query.exec()){
                return true;
        }else{
                return false;
        }
}

bool MySQLEmbeddedDatabase::removeWeapon(QString hash)
{
        QSqlQuery query;

        query.prepare("DELETE FROM weapon WHERE weapon.wp_hash = :hash");
        query.bindValue(":hash", hash);

        if(query.exec()){
                return true;
        }else{
                return false;
        }
}

bool MySQLEmbeddedDatabase::removeWeapon(uint id)
{
        QSqlQuery query;

        query.prepare("DELETE FROM weapon WHERE weapon.wp_id = :id");
        query.bindValue(":id", id);

        if(query.exec()){
                return true;
        }else{
                return false;
        }
}

bool MySQLEmbeddedDatabase::updateWeapon(Weapon *weapon)
{
        QSqlQuery query;

        if(this->weaponTypeExist(*weapon->getWeaponType())){
                if( this->updateWeaponType(weapon->getWeaponType()) == false ){
                        qDebug("Error while updating the WeaponType.");
                        return false;
                }
        }else{
                if( this->addWeaponType(weapon->getWeaponType()) == false ){
                        qDebug("Error while adding the WeaponType.");
                        return false;
                }
        }

        if(this->weaponDamageTypeExist(*weapon->getDamageType())){
                if( this->updateWeaponDamageType(weapon->getDamageType()) == false ){
                        qDebug("Error while updating the WeaponDamageType.");
                        return false;
                }
        }else{
                if( this->addWeaponDamageType(weapon->getDamageType()) == false ){
                        qDebug("Error while adding the WeaponDamageType.");
                        return false;
                }
        }

        query.prepare("UPDATE weapon SET"
                      "wp_hash = :hash,"
                      "wp_name = :name,"
                      "wp_desc = :desc,"
                      "wp_type_hash = :type_hash;"
                      "wp_price = :price,"
                      "wp_dmg_s = :dmg_s,"
                      "wp_dmg_m = :dmg_m,"
                      "wp_crit_fact = :crit_fact,"
                      "wp_crit_rng = :crit_rng,"
                      "wp_range = :range,"
                      "wp_weight = :weight,"
                      "wp_dmg_type_hash = :dmg_type_hash,"
                      "wp_ba_bonus = :ba_bonus,"
                      "wp_dmg_bonus = :dmg_bonus"
                      " WHERE weapon.wp_id = :id");

        query.bindValue(":hash", weapon->getHexHash());
        query.bindValue(":name", weapon->getName());
        query.bindValue(":desc", weapon->getDescription());
        query.bindValue(":type_hash", weapon->getWeaponType()->getHexHash());
        query.bindValue(":price", weapon->getPrice());
        query.bindValue(":dmg_s", weapon->getDamageSmall());
        query.bindValue(":dmg_m", weapon->getDamageMedium());
        query.bindValue(":crit_fact", weapon->getCriticalFactor());
        query.bindValue(":crit_rng", weapon->getCriticalRange());
        query.bindValue(":range", weapon->getRange());
        query.bindValue(":weight", weapon->getWeight());
        query.bindValue(":dmg_type_hash", weapon->getDamageType()->getHexHash());
        query.bindValue(":ba_bonus", weapon->getBaBonus());
        query.bindValue(":dmg_bonus", weapon->getDmgBonus());
        query.bindValue(":id", weapon->getId());

        if(query.exec()){
                return true;
        }else{
                return false;
        }
}

bool MySQLEmbeddedDatabase::getWeapon(uint id, Weapon *weapon)
{
        QSqlQuery query;

        query.setForwardOnly(true);

        query.prepare("SELECT wp_id, wp_name, wp_desc, wp_price, wp_dmg_s, wp_dmg_m, "
                        "wp_crit_fact, wp_crit_rng, wp_range, wp_weight, wp_ba_bonus, wp_dmg_bonus, "
                        "wp_type_hash, wp_dmg_type_hash "
                        " FROM weapon "
                        " WHERE weapon.wp_id = :id");

        query.bindValue(":id", id);

        if(query.exec()){
                weapon->setId(query.value(0).toUInt());
                weapon->setName(query.value(1).toString());
                weapon->setDescription(query.value(2).toString());
                weapon->setPrice(query.value(3).toDouble());
                weapon->setDamageSmall(query.value(4).toString());
                weapon->setDamageMedium(query.value(5).toString());
                weapon->setCriticalFactor(query.value(6).toUInt());
                weapon->setCriticalRange(query.value(7).toUInt());
                weapon->setRange(query.value(8).toDouble());
                weapon->setWeight(query.value(9).toDouble());
                weapon->setBaBonus(query.value(10).toInt());
                weapon->setDmgBonus(query.value(11).toInt());

                WeaponType type;
                if(this->getWeaponType(query.value(12).toString(), &type)){
                        weapon->setWeaponType(type);
                }else{
                        return false;
                }

                WeaponDamageType dmgType;
                if(this->getWeaponDamageType(query.value(13).toString(), &dmgType)){
                        weapon->setWeaponDamageType(dmgType);
                }else{
                        return false;
                }

                return true;
        }else{
                return false;
        }
}

bool MySQLEmbeddedDatabase::getWeapon(QString hash, Weapon * weapon)
{
        QSqlQuery query;

        query.setForwardOnly(true);

        query.prepare("SELECT wp_id, wp_name, wp_desc, wp_price, wp_dmg_s, wp_dmg_m, "
                        "wp_crit_fact, wp_crit_rng, wp_range, wp_weight, wp_ba_bonus, wp_dmg_bonus, "
                        "wp_type_hash, wp_dmg_type_hash "
                        " FROM weapon "
                        " WHERE weapon.wp_hash = :hash");

        query.bindValue(":hash", hash);

        if(query.exec()){
                weapon->setId(query.value(0).toUInt());
                weapon->setName(query.value(1).toString());
                weapon->setDescription(query.value(2).toString());
                weapon->setPrice(query.value(3).toDouble());
                weapon->setDamageSmall(query.value(4).toString());
                weapon->setDamageMedium(query.value(5).toString());
                weapon->setCriticalFactor(query.value(6).toUInt());
                weapon->setCriticalRange(query.value(7).toUInt());
                weapon->setRange(query.value(8).toDouble());
                weapon->setWeight(query.value(9).toDouble());
                weapon->setBaBonus(query.value(10).toInt());
                weapon->setDmgBonus(query.value(11).toInt());

                WeaponType type;
                if(this->getWeaponType(query.value(12).toString(), &type)){
                        weapon->setWeaponType(type);
                }else{
                        return false;
                }

                WeaponDamageType dmgType;
                if(this->getWeaponDamageType(query.value(13).toString(), &dmgType)){
                        weapon->setWeaponDamageType(dmgType);
                }else{
                        return false;
                }

                return true;
        }else{
                return false;
        }
}

bool MySQLEmbeddedDatabase::weaponExist(Weapon weapon)
{
        QSqlQuery query;
        query.prepare("SELECT wp_id FROM weapon WHERE weapon.wp_hash = :hash");
        query.bindValue(":hash",weapon.getHexHash());

        if(query.exec()){
                return query.next();    //return true if there is a record, false otherwise
        }else{
                return false;
        }

}

QList<Weapon> MySQLEmbeddedDatabase::getAllWeapons(){
        QList<Weapon> weaponList;
        QSqlQuery query;
        query.prepare("SELECT * FROM weapon");

        if(query.exec()){
                do{
                        Weapon weapon;

                        weapon.setId(query.value(0).toUInt());
                        weapon.setName(query.value(1).toString());
                        weapon.setDescription(query.value(2).toString());
                        weapon.setPrice(query.value(3).toDouble());
                        weapon.setDamageSmall(query.value(4).toString());
                        weapon.setDamageMedium(query.value(5).toString());
                        weapon.setCriticalFactor(query.value(6).toUInt());
                        weapon.setCriticalRange(query.value(7).toUInt());
                        weapon.setRange(query.value(8).toDouble());
                        weapon.setWeight(query.value(9).toDouble());
                        weapon.setBaBonus(query.value(10).toInt());
                        weapon.setDmgBonus(query.value(11).toInt());

                        WeaponType type;
                        if(this->getWeaponType(query.value(12).toString(), &type)){
                                weapon.setWeaponType(type);
                        }else{
                                qDebug("Could not retrieve weapon type " + query.value(12).toString().toUtf8());
                        }

                        WeaponDamageType dmgType;
                        if(this->getWeaponDamageType(query.value(13).toString(), &dmgType)){
                                weapon.setWeaponDamageType(dmgType);
                        }else{
                                qDebug("Could not retrieve weapon type " + query.value(13).toString().toUtf8());
                        }

                        weaponList.append(weapon);

                }while(query.exec());

                return weaponList;
        }else{
                qDebug("Could not retrieve weapon list");
                return QList<Weapon>();
        }
}

bool MySQLEmbeddedDatabase::addWeaponType(WeaponType *type)
{
        QSqlQuery query;
        query.prepare("INSERT INTO wp_type(wp_type_hash,wp_type_name,wp_type_type,wp_type_cat)"
                      " VALUES(:hash,:name,:type_name,:type_cat)");
        query.bindValue(":hash", type->getHexHash());
        query.bindValue(":name", type->getName());
        query.bindValue(":type_name", type->getType());
        query.bindValue(":type_cat", type->getCategory());

        if(query.exec()){
                type->setId(query.lastInsertId().toInt());
                return true;
        }else{
                return false;
        }
}

bool MySQLEmbeddedDatabase::removeWeaponType(WeaponType *type)
{
        QSqlQuery query;

        query.prepare("DELETE FROM wp_type WHERE wp_type.wp_type_hash = :hash");
        query.bindValue(":hash", type->getHexHash());

        if(query.exec()){
                return true;
        }else{
                return false;
        }
}

bool MySQLEmbeddedDatabase::removeWeaponType(QString hash)
{
        QSqlQuery query;

        query.prepare("DELETE FROM wp_type WHERE wp_type.wp_type_hash = :hash");
        query.bindValue(":hash", hash);

        if(query.exec()){
                return true;
        }else{
                return false;
        }
}

bool MySQLEmbeddedDatabase::removeWeaponType(uint id)
{
        QSqlQuery query;

        query.prepare("DELETE FROM wp_type WHERE wp_type.wp_type_id = :id");
        query.bindValue(":id", id);

        if(query.exec()){
                return true;
        }else{
                return false;
        }
}

bool MySQLEmbeddedDatabase::updateWeaponType(WeaponType *type)
{
        //cannot check if the record exist using the hash as it might have changed... maybe we should check it using the id

        QSqlQuery query;

        query.prepare("UPDATE wp_type SET wp_type_hash = :hash , wp_type_name = :name, wp_type_type = :type , wp_type_cat = :cat"
                      " WHERE wp_type_id = :id");
        query.bindValue(":hash", type->getHexHash());
        query.bindValue(":name", type->getName());
        query.bindValue(":type", type->getType());
        query.bindValue(":cat", type->getCategory());
        query.bindValue(":id", type->getId());

        if(query.exec()){
                return true;
        }else{
                return false;
        }
}

bool MySQLEmbeddedDatabase::getWeaponType(uint id, WeaponType *type)
{
        QSqlQuery query;

        query.setForwardOnly(true);

        query.prepare("SELECT wp_type_id, wp_type_name, wp_type_type, wp_type_cat "
                        " FROM wp_type "
                        " WHERE wp_type.wp_type_id = :id");

        query.bindValue(":id", id);

        if(query.exec()){
                type->setId(query.value(0).toUInt());
                type->setName(query.value(1).toString());
                type->setType(query.value(2).toString());
                type->setCategory(query.value(3).toString());

                return true;
        }else{
                return false;
        }
}

bool MySQLEmbeddedDatabase::getWeaponType(QString hash, WeaponType *type)
{
        QSqlQuery query;

        query.setForwardOnly(true);

        query.prepare("SELECT wp_type_id, wp_type_name, wp_type_type, wp_type_cat "
                        " FROM wp_type "
                        " WHERE wp_type.wp_type_hash = :hash");

        query.bindValue(":hash", hash);

        if(query.exec()){
                type->setId(query.value(0).toUInt());
                type->setName(query.value(1).toString());
                type->setType(query.value(2).toString());
                type->setCategory(query.value(3).toString());

                return true;
        }else{
                return false;
        }
}

bool MySQLEmbeddedDatabase::weaponTypeExist(WeaponType type)
{
        QSqlQuery query;
        query.prepare("SELECT wp_type_id FROM wp_type WHERE wp_type.wp_type_hash = :hash");
        query.bindValue(":hash", type.getHexHash());

        if(query.exec()){
                return query.next();    //return true if there is a record, false otherwise
        }else{
                return false;
        }
}

bool MySQLEmbeddedDatabase::addWeaponDamageType(WeaponDamageType *type)
{
        QSqlQuery query;
        query.prepare("INSERT INTO wp_dmg_type(wp_dmg_type_hash,wp_dmg_type_name)"
                      " VALUES(:hash,:name)");
        query.bindValue(":hash", type->getHexHash());
        query.bindValue(":name", type->getName());

        if(query.exec()){
                type->setId(query.lastInsertId().toInt());
                return true;
        }else{
                return false;
        }
}

bool MySQLEmbeddedDatabase::removeWeaponDamageType(WeaponDamageType *type)
{
        QSqlQuery query;

        query.prepare("DELETE FROM wp_dmg_type WHERE wp_dmg_type.wp_dmg_type_hash = :hash");
        query.bindValue(":hash", type->getHexHash());

        if(query.exec()){
                return true;
        }else{
                return false;
        }
}

bool MySQLEmbeddedDatabase::removeWeaponDamageType(QString hash)
{
        QSqlQuery query;

        query.prepare("DELETE FROM wp_dmg_type WHERE wp_dmg_type.wp_dmg_type_hash = :hash");
        query.bindValue(":hash", hash);

        if(query.exec()){
                return true;
        }else{
                return false;
        }
}

bool MySQLEmbeddedDatabase::removeWeaponDamageType(uint id)
{
        QSqlQuery query;

        query.prepare("DELETE FROM wp_dmg_type WHERE wp_dmg_type.wp_dmg_type_id = :id");
        query.bindValue(":id", id);

        if(query.exec()){
                return true;
        }else{
                return false;
        }
}

bool MySQLEmbeddedDatabase::updateWeaponDamageType(WeaponDamageType *type)
{
        //cannot check if the record exist using the hash as it might have changed... maybe we should check it using the id

        QSqlQuery query;

        query.prepare("UPDATE wp_dmg_type SET wp_dmg_type_hash = :hash , wp_dmg_type_name = :name"
                      " WHERE wp_dmg_type_id = :id");
        query.bindValue(":hash", type->getHexHash());
        query.bindValue(":name", type->getName());
        query.bindValue(":id", type->getId());

        if(query.exec()){
                return true;
        }else{
                return false;
        }
}

bool MySQLEmbeddedDatabase::getWeaponDamageType(uint id, WeaponDamageType *type)
{
        QSqlQuery query;

        query.setForwardOnly(true);

        query.prepare("SELECT wp_dmg_type_id, wp_dmg_type_name "
                        " FROM wp_dmg_type "
                        " WHERE wp_dmg_type.wp_dmg_type_id = :id");

        query.bindValue(":id", id);

        if(query.exec()){
                type->setId(query.value(0).toUInt());
                type->setName(query.value(1).toString());

                return true;
        }else{
                return false;
        }
}

bool MySQLEmbeddedDatabase::getWeaponDamageType(QString hash, WeaponDamageType *type)
{
        QSqlQuery query;

        query.setForwardOnly(true);

        query.prepare("SELECT wp_dmg_type_id, wp_dmg_type_name "
                        " FROM wp_dmg_type "
                        " WHERE wp_dmg_type.wp_dmg_type_hash = :hash");

        query.bindValue(":hash", hash);

        if(query.exec()){
                type->setId(query.value(0).toUInt());
                type->setName(query.value(1).toString());

                return true;
        }else{
                return false;
        }
}

bool MySQLEmbeddedDatabase::weaponDamageTypeExist(WeaponDamageType type)
{
        QSqlQuery query;
        query.prepare("SELECT wp_dmg_type_id FROM wp_dmg_type WHERE wp_dmg_type.wp_dmg_type_hash = :hash");
        query.bindValue(":hash", type.getHexHash());

        if(query.exec()){
                return query.next();    //return true if there is a record, false otherwise
        }else{
                return false;
        }
}
